﻿using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using K9Nano.Application.Features;
using K9Nano.AspNetCore.Extensions;
using K9Nano.Authorization;
using K9Nano.Share.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;

namespace K9Nano.AspNetCore.Authorization
{
    public class K9RbacRequirementHandler : AuthorizationHandler<K9RbacRequirement>
    {
        private readonly IRbacChecker _rbacChecker;
        private readonly ILogger _logger;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IFeatureChecker _featureChecker;

        public K9RbacRequirementHandler(ILogger<K9RbacRequirementHandler> logger, IRbacChecker rbacChecker, IHttpContextAccessor httpContextAccessor, IFeatureChecker featureChecker)
        {
            _rbacChecker = rbacChecker;
            _httpContextAccessor = httpContextAccessor;
            _featureChecker = featureChecker;
            _logger = logger;
        }

        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, K9RbacRequirement requirement)
        {
            if (!context.User.Identity.IsAuthenticated)
            {
                context.Fail();
            }
            if (context.Resource is RouteEndpoint routeEndpoint)
            {
                var controllerActionDescriptor = routeEndpoint.Metadata.OfType<ControllerActionDescriptor>().FirstOrDefault();
                if (controllerActionDescriptor == null)
                {
                    throw new K9BrokenChangeException("Breaking changes: Can not access Controller");
                }

                var apiResource = controllerActionDescriptor.ToApiResource();

                /* 检查租户的功能 */
                var requiredFeature =
                    controllerActionDescriptor.MethodInfo.GetCustomAttribute<RequiresFeatureAttribute>(true)
                    ?? controllerActionDescriptor.ControllerTypeInfo.GetCustomAttribute<RequiresFeatureAttribute>(true);
                if (requiredFeature != null)
                {
                    if (!await _featureChecker.IsEnabledAsync(requiredFeature.RequiresAll, requiredFeature.Features))
                    {
                        _logger.LogInformation($"当前租户无权访问{apiResource}");
                        context.Fail();
                    }
                }

                /* 检查用户权限 */
                if (await _rbacChecker.ValidateAsync(apiResource, _httpContextAccessor.HttpContext.RequestAborted))
                {
                    context.Succeed(requirement);
                }
                else
                {
                    _logger.LogInformation($"当前用户无权访问{apiResource}");
                }

            }
            else
            {
                throw new K9BrokenChangeException();
            }
        }
    }
}